package com.adjy.pathbuilders.sounds;

import java.io.IOException;
import java.util.HashMap;

import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.SoundPool;
import android.util.Log;

import com.adjy.pathbuilders.rendering.loading.ImageFileParser;

public class SoundManager {
	
	private static final String SOUND_FILE = "sounds_file";
	
	private static SoundManager soundManager = null;
	
	private Context context;
	
	private MediaPlayer mediaPlayer;
	private SoundPool soundPool;
	
	private HashMap<String, Integer> loadedEffects;
	private HashMap<String, String> soundPaths;
	
	private boolean playBackActive;

	private float volume;
	
	public SoundManager(Context c) {
		this.playBackActive = true;
		this.volume = 100;
		context = c;
		mediaPlayer = new MediaPlayer();
	    mediaPlayer.setLooping(true);
		soundPool = new SoundPool(20, AudioManager.STREAM_MUSIC, 0);
		
		soundPaths = new HashMap<String, String>();
		loadedEffects = new HashMap<String, Integer>();
		
		loadSoundDescriptions();
	}
	
	private void loadSoundDescriptions() {
		
		try {
			HashMap<String, String[]> descriptions = ImageFileParser.parseImageFile(context.getAssets().open(SOUND_FILE));
			
			for (String id : descriptions.keySet()) {
				soundPaths.put(id, descriptions.get(id)[0]);
			}
			
		} catch (IOException e) {
			// Handle Error
		} catch (IndexOutOfBoundsException e) {
			// Handle Error
		}
	}
	
	public void playMusic(String musicId) {
		if (soundPaths.containsKey(musicId)) {
		    try {
		    	AssetFileDescriptor afd = context.getAssets().openFd(soundPaths.get(musicId));
				if (mediaPlayer.isPlaying()) {
					mediaPlayer.stop();
				}
				mediaPlayer.reset();
				mediaPlayer.setDataSource(afd.getFileDescriptor(),afd.getStartOffset(),afd.getLength());
				afd.close();
			    mediaPlayer.prepare();
			    mediaPlayer.start();
			    mediaPlayer.setLooping(true);
			} catch (IllegalArgumentException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalStateException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		} else {
			Log.e("SoundManager", "Music ID (" + musicId + ") not found");
		}
	}
	
	public void resumeMusic() {
		mediaPlayer.start();
	}
	
	public void stopMusic() {
		mediaPlayer.stop();
	}
	
	public void pauseMusic() {
		mediaPlayer.pause();
	}
	
	public void playSoundEffect(String soundId) {
		if (loadedEffects.containsKey(soundId)) {
			if (playBackActive)
				soundPool.play(loadedEffects.get(soundId), this.volume, this.volume, 1, 0, 1); // TODO: Get Volume
		} else {
			Log.e("SoundManager", "Attempted to play a sound not loaded (" + soundId +")");
		}
	}
	
	public void loadSoundEffects(String... ids) {
		
		for (String id : ids) {
			
			if (loadedEffects.containsKey(id)) {
				Log.i("SoundManager", "SoundEffect (" + id + ") already loaded");
			} else {
				try {
					int effectId = soundPool.load(
							context.getAssets().openFd(soundPaths.get(id)), 1);
					
					if (effectId != 0) { 
						loadedEffects.put(id, effectId);
					} else {
						Log.e("SoundManager", "Failed While Loading Sound Effect (" + id + ")");
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	public void releaseSoundEffects(String... ids) {
		for (String id : ids) {
			if (loadedEffects.containsKey(id)) {
				soundPool.unload(loadedEffects.get(id));
			}
		}
	}
	
	public void startAllSounds() {
		playBackActive = true;
		mediaPlayer.start();
	}
	
	public void stopAllSounds() {
		playBackActive = false;
		mediaPlayer.stop();
	}
	
	private void destroyManagers() {
		mediaPlayer.release();
		soundPool.release();
	}
	
	// Singleton Methods
	
	public static void create(Context context) {
		if (soundManager != null) {
			SoundManager.destroy();
		}
		soundManager = new SoundManager(context);
	}
	
	public static SoundManager getInstance() {
		return soundManager;
	}
	
	public float getVolume() {
		return volume;
	}
	
	public void setVolume(float volume) {
		if(volume>=0 && volume <= 100){ 
			this.volume = volume/100;
			this.mediaPlayer.setVolume(this.volume, this.volume);
		}
	}
	
	public static void destroy() {
		if (soundManager != null) {
			soundManager.destroyManagers();
			soundManager = null;
		}
	}
}
